﻿/* 
 * Enterprise Library Extensions - DI + ORM.
 * Copyright (C) 2006
 *
 * GNU General Public License
 *
 * This program is free software; you can redistribute 
 * it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation; either version 2 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 */
#region Using directives

using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Xml;
using ELE.Common.Util;

#endregion

namespace ELE.EnterpriseLibrary.Naming.Configuration
{
  /// <summary>
  /// 
  /// </summary>
	public class ComponentConfigurationParser : GenericConfigurationParser
	{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public static ComponentConfiguration ParseComponentConfiguration(string fileName)
    {
      if (fileName == null || !File.Exists(fileName))
      {
        //TODO:Throw an exception here
        return null;
      }
      XmlDocument doc = XML.Parse(fileName);
      if (doc.SelectSingleNode(ComponentConfiguration.TAGNAME_COMPONENT) == null)
      {
        return null;
      }
      XmlNode typeNode = SelectNodeByNameIgnoreCase(doc.DocumentElement, ComponentConfiguration.TAGNAME_TYPE);
      ComponentConfiguration conf = new ComponentConfiguration();
      object typeObj = GetClassAssemblyPairFromNode(typeNode);
      if (typeObj != null)
      {
        if (typeObj is ClassAssemblyPair)
        {
          conf.ComponentType = (ClassAssemblyPair)typeObj;
        }
        else if (typeObj is string)
        {
          conf.ComponentType = new ClassAssemblyPair((string)typeObj);
        }
        XmlNode factoryNode = SelectNodeByNameIgnoreCase(doc.DocumentElement, ComponentConfiguration.TAGNAME_FACTORY);
        if (factoryNode != null && factoryNode.HasChildNodes)
        {
          ComponentInitializationFactory factory = new ComponentInitializationFactory();
          factory.FactoryType = GetClassAssemblyPairFromNode(factoryNode);
          XmlNode factoryMethodNode = SelectNodeByNameIgnoreCase(factoryNode, ComponentConfiguration.TAGNAME_METHOD);
          if (factoryMethodNode != null && factoryMethodNode.Attributes[ComponentConfiguration.ATTRIBUTENAME_NAME] != null)
          {
            factory.FactoryMethod = factoryMethodNode.Attributes[ComponentConfiguration.ATTRIBUTENAME_NAME].Value;
            if (factoryMethodNode.HasChildNodes)
            {
              foreach (XmlNode argumentNode in factoryNode.ChildNodes)
              {
                if (argumentNode.Name == GenericConfiguration.TAGNAME_PARAM)
                {
                  factory.AddParameter(GetComponentInitializer(argumentNode));
                }
              }
            }
            conf.Factory = factory;
          }
          //else Probably throw an exception????
        }
        XmlNode methodsNode = SelectNodeByNameIgnoreCase(doc.DocumentElement,ComponentConfiguration.TAGNAME_METHODS);
        if (methodsNode != null && methodsNode.HasChildNodes)
        {
          foreach (XmlNode methodNode in methodsNode.ChildNodes)
          {
            if (methodNode.Name == GenericConfiguration.TAGNAME_ADD)
            {
              ComponentInitializer methodDef = new ComponentInitializer();
              methodDef.Name = methodNode.Attributes[GenericConfiguration.ATTRIBUTENAME_NAME].Value;
              if (methodNode.HasChildNodes)
              {
                ComponentInitializerCollection paramList = new ComponentInitializerCollection();
                foreach (XmlNode methodParamNode in methodNode.ChildNodes)
                {
                  if (methodParamNode.Name == GenericConfiguration.TAGNAME_PARAM)
                  {
                    ComponentInitializer methodParam = new ComponentInitializer();
                    methodParam.Name = methodParamNode.Attributes[GenericConfiguration.ATTRIBUTENAME_NAME].Value;
                    paramList.Add(GetComponentInitializer(methodParamNode));
                  }
                }
                methodDef.Value = paramList;
              }
              conf.AddMethod(methodDef);
            }
          }
        }
        XmlNode propertiesNode = SelectNodeByNameIgnoreCase(doc.DocumentElement, ComponentConfiguration.TAGNAME_PROPERTIES);
        if (propertiesNode != null && propertiesNode.HasChildNodes)
        {
          foreach (XmlNode propertyNode in propertiesNode.ChildNodes)
          {
            if (propertyNode.Name == GenericConfiguration.TAGNAME_ADD)
            {
              conf.AddProperty(GetComponentInitializer(propertyNode));
            }
          }
        }
        XmlNode constructorArgumentsNode = SelectNodeByNameIgnoreCase(doc.DocumentElement, ComponentConfiguration.TAGNAME_CONSTRUCTOR);
        if (constructorArgumentsNode != null && constructorArgumentsNode.HasChildNodes)
        {
          foreach (XmlNode argumentNode in constructorArgumentsNode.ChildNodes)
          {
            if (argumentNode.Name == GenericConfiguration.TAGNAME_PARAM)
            {
              conf.AddConstructorArgument(GetComponentInitializer(argumentNode));
            }
          }
        }
        XmlNode remotingNode = SelectNodeByNameIgnoreCase(doc.DocumentElement, ComponentConfiguration.TAGNAME_REMOTING);
        if (remotingNode != null)
        {
          RemotingComponentConfiguration remotingConf = new RemotingComponentConfiguration();
          XmlNode remotingObjectModeNode = SelectNodeByNameIgnoreCase(remotingNode, ComponentConfiguration.TAGNAME_REMOTING_OBJECTMODE);
          if(remotingObjectModeNode != null)
          {
            remotingConf.ObjectMode = remotingObjectModeNode.InnerText;
          }
          conf.Remoting = remotingConf;
        }
        return conf;
      }
      return null;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    public static ComponentInitializer GetComponentInitializer(XmlNode node)
    {
      ComponentInitializer initializer = new ComponentInitializer();
      initializer.Name = node.Attributes[GenericConfiguration.ATTRIBUTENAME_NAME].Value;
      initializer.Type = ComponentInitializer.TYPE_VALUE;
      if (node.HasChildNodes)
      {
        if (node.FirstChild.NodeType.Equals(XmlNodeType.Text))
        {
          initializer.Value = node.InnerText;
        }
        else
        {
          XmlNode refNode = SelectNodeByNameIgnoreCase(node, ComponentConfiguration.TAGNAME_REFERENCE);
          if (refNode != null)
          {
            initializer.Value = refNode.InnerText;
            initializer.Type = ComponentInitializer.TYPE_REF;
          }
          else
          {
            initializer.Value = GetComponentNodeValue(node);
          }
        }
      }
      return initializer;
    }
  }
}
